// arduino_data_collector.ino - 工业数据采集节点Arduino代码
#include <ModbusMaster.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// 引脚定义
#define ONE_WIRE_BUS 2       // DS18B20温度传感器引脚
#define TEMP1_PIN A0         // 温度传感器1模拟输入引脚
#define TEMP2_PIN A1         // 温度传感器2模拟输入引脚
#define PRESSURE1_PIN A2     // 压力传感器1模拟输入引脚
#define PRESSURE2_PIN A3     // 压力传感器2模拟输入引脚
#define VIBRATION1_PIN A4    // 振动传感器1模拟输入引脚
#define VIBRATION2_PIN A5    // 振动传感器2模拟输入引脚
#define ALARM_LED_PIN 13     // 报警LED引脚
#define STATUS_LED_PIN 12    // 状态LED引脚
#define RS485_TX_PIN 10      // RS485通信TX引脚
#define RS485_RX_PIN 11      // RS485通信RX引脚
#define RS485_DE_PIN 9       // RS485通信DE/RE引脚

// 创建Modbus主从机对象
ModbusMaster node;

// 创建OneWire和DallasTemperature对象
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// 阈值定义
#define TEMP_HIGH_THRESHOLD 80.0    // 温度高阈值(℃)
#define TEMP_LOW_THRESHOLD 0.0      // 温度低阈值(℃)
#define PRESSURE_HIGH_THRESHOLD 10.0 // 压力高阈值(bar)
#define PRESSURE_LOW_THRESHOLD 0.0  // 压力低阈值(bar)
#define VIBRATION_THRESHOLD 3.0     // 振动阈值(V)

// 数据变量
float temperature1 = 0.0;
float temperature2 = 0.0;
float pressure1 = 0.0;
float pressure2 = 0.0;
float vibration1 = 0.0;
float vibration2 = 0.0;
float ds18b20_temperature = 0.0;

// 系统状态
bool system_ok = true;
bool temperature_alarm = false;
bool pressure_alarm = false;
bool vibration_alarm = false;

// 通信地址
#define DEVICE_ID 1           // 设备ID
#define MODBUS_BAUD 9600      // Modbus通信波特率

// 定时变量
unsigned long last_status_update = 0;
unsigned long last_data_read = 0;
unsigned long last_modbus_communication = 0;
const unsigned long STATUS_UPDATE_INTERVAL = 1000;  // 状态LED闪烁间隔
const unsigned long DATA_READ_INTERVAL = 500;       // 数据读取间隔
const unsigned long MODBUS_COMM_INTERVAL = 2000;    // Modbus通信间隔

void setup() {
  // 初始化串口通信(用于调试)
  Serial.begin(9600);
  while (!Serial) {
    ; // 等待串口连接
  }
  Serial.println("工业数据采集节点启动中...");
  
  // 初始化引脚模式
  pinMode(ALARM_LED_PIN, OUTPUT);
  pinMode(STATUS_LED_PIN, OUTPUT);
  pinMode(RS485_DE_PIN, OUTPUT);
  digitalWrite(RS485_DE_PIN, LOW); // 默认接收模式
  
  // 初始化Modbus通信
  node.begin(DEVICE_ID, Serial1);
  Serial1.begin(MODBUS_BAUD);
  
  // 初始化DS18B20温度传感器
  sensors.begin();
  
  // 初始化完成
  digitalWrite(STATUS_LED_PIN, HIGH);
  delay(1000);
  digitalWrite(STATUS_LED_PIN, LOW);
  Serial.println("工业数据采集节点初始化完成");
}

void loop() {
  unsigned long current_time = millis();
  
  // 更新状态LED
  if (current_time - last_status_update >= STATUS_UPDATE_INTERVAL) {
    updateStatusLED();
    last_status_update = current_time;
  }
  
  // 读取传感器数据
  if (current_time - last_data_read >= DATA_READ_INTERVAL) {
    readSensorData();
    checkThresholds();
    last_data_read = current_time;
  }
  
  // 与Modbus设备通信
  if (current_time - last_modbus_communication >= MODBUS_COMM_INTERVAL) {
    communicateWithModbus();
    last_modbus_communication = current_time;
  }
  
  // 更新报警LED
  updateAlarmLED();
}

// 读取传感器数据
void readSensorData() {
  // 读取温度传感器
  temperature1 = readTemperatureSensor(TEMP1_PIN);
  temperature2 = readTemperatureSensor(TEMP2_PIN);
  
  // 读取DS18B20温度传感器
  ds18b20_temperature = readDS18B20Temperature();
  
  // 读取压力传感器
  pressure1 = readPressureSensor(PRESSURE1_PIN);
  pressure2 = readPressureSensor(PRESSURE2_PIN);
  
  // 读取振动传感器
  vibration1 = readVibrationSensor(VIBRATION1_PIN);
  vibration2 = readVibrationSensor(VIBRATION2_PIN);
  
  // 打印传感器数据(调试用)
  /*
  Serial.print("温度1: ");
  Serial.print(temperature1);
  Serial.println(" °C");
  Serial.print("温度2: ");
  Serial.print(temperature2);
  Serial.println(" °C");
  Serial.print("DS18B20温度: ");
  Serial.print(ds18b20_temperature);
  Serial.println(" °C");
  Serial.print("压力1: ");
  Serial.print(pressure1);
  Serial.println(" bar");
  Serial.print("压力2: ");
  Serial.print(pressure2);
  Serial.println(" bar");
  Serial.print("振动1: ");
  Serial.print(vibration1);
  Serial.println(" V");
  Serial.print("振动2: ");
  Serial.print(vibration2);
  Serial.println(" V");
  */
}

// 读取模拟温度传感器
float readTemperatureSensor(int pin) {
  // 这里假设使用的是PT100或类似的温度传感器
  // 实际应用中需要根据传感器类型调整转换公式
  int sensorValue = analogRead(pin);
  // 简单转换：假设0-1023对应0-100℃
  float temperature = (sensorValue / 1023.0) * 100.0;
  return temperature;
}

// 读取DS18B20温度传感器
float readDS18B20Temperature() {
  sensors.requestTemperatures();
  float tempC = sensors.getTempCByIndex(0);
  // 检查温度是否有效
  if (tempC == DEVICE_DISCONNECTED_C) {
    Serial.println("DS18B20传感器连接断开");
    return 0.0;
  }
  return tempC;
}

// 读取压力传感器
float readPressureSensor(int pin) {
  // 这里假设使用的是0-10V输出的压力传感器(0-10bar)
  int sensorValue = analogRead(pin);
  // 将0-1023转换为0-10bar
  float pressure = (sensorValue / 1023.0) * 10.0;
  return pressure;
}

// 读取振动传感器
float readVibrationSensor(int pin) {
  // 读取振动传感器的模拟值
  int sensorValue = analogRead(pin);
  // 将0-1023转换为0-5V
  float voltage = (sensorValue / 1023.0) * 5.0;
  return voltage;
}

// 检查阈值
void checkThresholds() {
  // 重置报警状态
  temperature_alarm = false;
  pressure_alarm = false;
  vibration_alarm = false;
  system_ok = true;
  
  // 检查温度阈值
  if (temperature1 > TEMP_HIGH_THRESHOLD || temperature1 < TEMP_LOW_THRESHOLD ||
      temperature2 > TEMP_HIGH_THRESHOLD || temperature2 < TEMP_LOW_THRESHOLD ||
      ds18b20_temperature > TEMP_HIGH_THRESHOLD || ds18b20_temperature < TEMP_LOW_THRESHOLD) {
    temperature_alarm = true;
    system_ok = false;
  }
  
  // 检查压力阈值
  if (pressure1 > PRESSURE_HIGH_THRESHOLD || pressure1 < PRESSURE_LOW_THRESHOLD ||
      pressure2 > PRESSURE_HIGH_THRESHOLD || pressure2 < PRESSURE_LOW_THRESHOLD) {
    pressure_alarm = true;
    system_ok = false;
  }
  
  // 检查振动阈值
  if (vibration1 > VIBRATION_THRESHOLD || vibration2 > VIBRATION_THRESHOLD) {
    vibration_alarm = true;
    system_ok = false;
  }
  
  // 如果有报警，记录到串口
  if (!system_ok) {
    Serial.println("警告：检测到异常情况！");
    if (temperature_alarm) Serial.println("- 温度异常");
    if (pressure_alarm) Serial.println("- 压力异常");
    if (vibration_alarm) Serial.println("- 振动异常");
  }
}

// 与Modbus设备通信
void communicateWithModbus() {
  // 转换浮点数为Modbus寄存器格式
  uint16_t temp1_reg[2];
  uint16_t temp2_reg[2];
  uint16_t ds18b20_reg[2];
  uint16_t pressure1_reg[2];
  uint16_t pressure2_reg[2];
  uint16_t vibration1_reg[2];
  uint16_t vibration2_reg[2];
  uint16_t status_reg;
  
  // 将浮点数转换为Modbus寄存器
  floatToWord(temperature1, temp1_reg);
  floatToWord(temperature2, temp2_reg);
  floatToWord(ds18b20_temperature, ds18b20_reg);
  floatToWord(pressure1, pressure1_reg);
  floatToWord(pressure2, pressure2_reg);
  floatToWord(vibration1, vibration1_reg);
  floatToWord(vibration2, vibration2_reg);
  
  // 设置状态寄存器
  status_reg = 0;
  if (!system_ok) status_reg |= 0x01;
  if (temperature_alarm) status_reg |= 0x02;
  if (pressure_alarm) status_reg |= 0x04;
  if (vibration_alarm) status_reg |= 0x08;
  
  // 发送Modbus请求（写入保持寄存器）
  digitalWrite(RS485_DE_PIN, HIGH); // 设置为发送模式
  delay(1); // 等待RS485模式切换
  
  // 尝试写入数据到Modbus寄存器
  uint8_t result = node.writeMultipleRegisters(0, 15, (
    uint16_t[]){
      temp1_reg[0], temp1_reg[1],        // 寄存器0-1: 温度1
      temp2_reg[0], temp2_reg[1],        // 寄存器2-3: 温度2
      ds18b20_reg[0], ds18b20_reg[1],    // 寄存器4-5: DS18B20温度
      pressure1_reg[0], pressure1_reg[1], // 寄存器6-7: 压力1
      pressure2_reg[0], pressure2_reg[1], // 寄存器8-9: 压力2
      vibration1_reg[0], vibration1_reg[1], // 寄存器10-11: 振动1
      vibration2_reg[0], vibration2_reg[1], // 寄存器12-13: 振动2
      status_reg                         // 寄存器14: 状态寄存器
    }
  ));
  
  delay(1); // 等待数据发送完成
  digitalWrite(RS485_DE_PIN, LOW); // 恢复到接收模式
  
  // 检查Modbus通信结果
  if (result == node.ku8MBSuccess) {
    // 通信成功
    Serial.println("Modbus数据发送成功");
    // 这里可以添加接收Modbus指令的代码
  } else {
    // 通信失败
    Serial.print("Modbus通信失败, 错误代码: ");
    Serial.println(result);
  }
}

// 浮点数转换为Modbus寄存器格式
void floatToWord(float value, uint16_t* reg) {
  // 创建联合体以实现类型转换
  union {
    float f;
    uint16_t u[2];
  } data;
  
  data.f = value;
  reg[0] = data.u[0];
  reg[1] = data.u[1];
}

// 更新状态LED
void updateStatusLED() {
  static bool status_led_state = false;
  status_led_state = !status_led_state;
  digitalWrite(STATUS_LED_PIN, status_led_state);
}

// 更新报警LED
void updateAlarmLED() {
  if (!system_ok) {
    // 报警状态：闪烁
    static unsigned long last_alarm_blink = 0;
    static bool alarm_led_state = false;
    
    if (millis() - last_alarm_blink >= 200) {
      alarm_led_state = !alarm_led_state;
      digitalWrite(ALARM_LED_PIN, alarm_led_state);
      last_alarm_blink = millis();
    }
  } else {
    // 正常状态：关闭
    digitalWrite(ALARM_LED_PIN, LOW);
  }
}

// PLC梯形图逻辑（概念实现，实际PLC编程需使用专业软件）
/*
PLC梯形图逻辑主要包括以下部分:
1. 初始化模块：设置通信参数、传感器阈值等
2. 数据采集模块：从Arduino接收传感器数据
3. 数据处理模块：对数据进行滤波、转换等处理
4. 阈值检查模块：检查各参数是否超过阈值
5. 通信模块：与上位机(Flask服务)通信
6. 本地控制模块：根据状态控制输出
7. 故障处理模块：处理各类异常情况

由于实际PLC编程需要使用专业软件，这里仅提供概念实现
*/